﻿using BaseUtils.Helper;
using BaseUtils.Logger;
using ExtendedNumerics;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Web.UI.WebControls;

namespace BaseUtils.Utils
{
    public class FileHelper
    {
        /// <summary>
        /// 复制文件
        /// </summary>
        /// <param name="SourceFile">源文件路径</param>
        /// <param name="DestinationFile">目标文件路径</param>
        /// <returns>是否复制成功</returns>
        public static bool CopeFile(string SourceFile, string DestinationFile)
        {
            try
            {
                File.Copy(SourceFile, DestinationFile);
            }
            catch (Exception ex)
            {
                LoggerService.Error($"文件复制失败，失败原因：{ex.Message}", ex);
                return false;
            }
            return true;
        }

        /// <summary>
        /// 读取文件内容
        /// </summary>
        /// <param name="Path">文件路径</param>
        /// <returns>文件内容</returns>
        public static string ReadContent(string Path)
        {
            if (!File.Exists(Path))
            {
                return null;
            }
            return File.ReadAllText(Path);
        }

        /// <summary>
        /// 使用StreamReader读取文件内容
        /// </summary>
        /// <param name="path">文件路径</param>
        /// <param name="NumLines">读取行数，0表示全部，正数表示从开头读，负数表示从结尾读</param>
        /// <param name="EncodingFormat">编码格式</param>
        /// <returns>读取的内容列表</returns>
        public static List<string> ReadContentWithStreamReader(string path, int NumLines = 0, string EncodingFormat = "UTF-8")
        {
            if (!File.Exists(path))
            {
                return null;
            }
            if (string.IsNullOrEmpty(EncodingFormat))
            {
                EncodingFormat = "UTF-8";
            }
            try
            {
                List<string> content = new List<string>();
                using (StreamReader reader = new StreamReader(path, Encoding.GetEncoding(EncodingFormat)))
                {
                    int originalNumLines = NumLines;
                    if (NumLines == 0)
                    {
                        // 读取全部内容
                        string line;
                        while ((line = reader.ReadLine()) != null)
                        {
                            content.Add(line);
                        }
                    }
                    else if (NumLines > 0)
                    {
                        // 从文件开头往下读指定行数
                        string line;
                        int count = 0;
                        while ((line = reader.ReadLine()) != null && count < NumLines)
                        {
                            content.Add(line);
                            count++;
                        }
                    }
                    else
                    {
                        // NumLines为负数，从文件末尾往上读指定行数（取绝对值）
                        NumLines = Math.Abs(NumLines);
                        long fileLength = new FileInfo(path).Length;
                        long currentPosition = fileLength;
                        // 从文件末尾往前逐行读取
                        while (NumLines > 0 && currentPosition > 0)
                        {
                            currentPosition--;
                            reader.BaseStream.Seek(currentPosition, SeekOrigin.Begin);
                            if ((char)reader.BaseStream.ReadByte() == '\n')
                            {
                                NumLines--;
                                if (NumLines == 0)
                                {
                                    break;
                                }
                            }
                        }
                        // 开始读取指定行数
                        string line;
                        while ((line = reader.ReadLine()) != null && NumLines < Math.Abs(originalNumLines))
                        {
                            content.Add(line);
                            NumLines++;
                        }
                        content.Reverse();  // 反转列表顺序，使其符合正常阅读习惯
                    }
                    return content;
                }
            }
            catch (Exception ex)
            {
                LoggerService.Error("文件读取错误", ex);
                return null;
            }
        }

        /// <summary>
        /// 读取文件内容并转换为指定类型
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <param name="Path">文件路径</param>
        /// <returns>转换后的对象</returns>
        public static T ReadContent<T>(string Path)
        {
            string C = ReadContent(Path);

            if (C == null)
            {
                return default(T);
            }

            return ConvertHelper.ToObject<T>(C);
        }

        /// <summary>
        /// 写入内容到文件
        /// </summary>
        /// <param name="PathAndName">文件路径和名称</param>
        /// <param name="Content">要写入的内容</param>
        private static void WriteContent(string PathAndName, string Content)
        {
            File.WriteAllText(PathAndName, Content);
        }

        /// <summary>
        /// 写入内容到文件
        /// </summary>
        /// <param name="Path">路径</param>
        /// <param name="FileName">文件名</param>
        /// <param name="Content">要写入的内容</param>
        public static void WriteContent(string Path, string FileName, string Content)
        {
            if (!Directory.Exists(Path))
            {
                Directory.CreateDirectory(Path);
            }
            WriteContent(Path + FileName, Content);
        }

        /// <summary>
        /// 写入CSV文件
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="Data">数据</param>
        /// <param name="Header">表头</param>
        /// <returns>是否写入成功</returns>
        public static bool WriteToCsv(string FilePath, List<string[]> Data, List<string[]> Header = null)
        {
            try
            {
                // 确保文件路径所在的目录存在
                string directory = Path.GetDirectoryName(FilePath);
                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }
                // 使用StreamWriter写入文件
                using (StreamWriter writer = new StreamWriter(FilePath, false, Encoding.UTF8))
                {
                    if (!File.Exists(FilePath) && Header != null && Header.Count > 0)
                    {
                        // 写入表头
                        string headerLine = string.Join(",", Header[0]);
                        writer.WriteLine(headerLine);
                    }

                    // 写入数据行
                    foreach (var row in Data)
                    {
                        string dataLine = string.Join(",", row);
                        writer.WriteLine(dataLine);
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                // 输出异常信息
                LoggerService.Error($"写入文件时出错: {ex.Message}", ex);
                return false;
            }
        }

        /// <summary>
        /// 读取CSV文件
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <param name="hasHeader">是否有表头</param>
        /// <returns>读取的数据</returns>
        public static List<string[]> ReadFromCsv(string filePath, bool hasHeader = true)
        {
            List<string[]> data = new List<string[]>();
            try
            {
                // 检查文件是否存在
                if (!File.Exists(filePath))
                {
                    Console.WriteLine("文件不存在。");
                    return data;
                }
                // 使用StreamReader读取文件
                using (StreamReader reader = new StreamReader(filePath, Encoding.UTF8))
                {
                    if (hasHeader)
                    {
                        // 跳过表头
                        reader.ReadLine();
                    }
                    string line;
                    while ((line = reader.ReadLine()) != null)
                    {
                        // 分割每行数据
                        string[] values = line.Split(',');
                        data.Add(values);
                    }
                }
            }
            catch (Exception ex)
            {
                // 输出异常信息
                Console.WriteLine($"读取文件时出错: {ex.Message}");
            }
            return data;
        }

        /// <summary>
        /// 创建文件夹
        /// </summary>
        /// <param name="DirectoryPath">文件夹路径</param>
        /// <returns>是否创建成功</returns>
        public static bool CreateDirectory(string DirectoryPath)
        {
            if (!Directory.Exists(DirectoryPath))
            {
                Directory.CreateDirectory(DirectoryPath);
            }
            return true;
        }

        /// <summary>
        /// 安全新增或更新JSON文件中的属性
        /// - 若目标属性不存在：在指定路径的父对象下新增该属性
        /// - 若目标属性已存在：直接更新属性值
        /// </summary>
        /// <param name="jsonFilePath">JSON文件路径</param>
        /// <param name="fullPropPath">完整属性路径（例：$.app.user.email，email为要新增/更新的属性）</param>
        /// <param name="propValue">属性值（支持字符串、数值、布尔等基础类型）</param>
        /// <returns>结构化更新结果（含成功/失败提示）</returns>
        public static UpdateResult SafeAddOrUpdateProperty(string jsonFilePath, string fullPropPath, object propValue)
        {
            // 步骤1：基础校验（文件路径、属性路径格式）
            var baseCheck = ValidateBaseInfo(jsonFilePath, fullPropPath);
            if (!baseCheck.IsSuccess)
            {
                return baseCheck;
            }

            // 步骤2：拆分“父对象路径”和“目标属性名”
            int lastDotIndex = fullPropPath.LastIndexOf('.');
            if (lastDotIndex <= 2) // 至少需满足 $.父.子 格式（$.a.b 中 lastDotIndex > 2）
            {
                return new UpdateResult
                {
                    IsSuccess = false,
                    Message = "属性路径格式错误：需包含父对象（例：$.app.user.email，不能是 $.email）",
                    TargetPath = fullPropPath
                };
            }
            string parentPath = fullPropPath.Substring(0, lastDotIndex); // 父对象路径
            string targetPropName = fullPropPath.Substring(lastDotIndex + 1); // 目标属性名

            JToken rootNode = null;
            string oldValue = null;
            string newValueStr = JsonConvert.SerializeObject(propValue);

            try
            {
                // 步骤3：加载文件并解析
                var loadResult = LoadJsonWithCheck(jsonFilePath);
                if (!loadResult.IsSuccess)
                {
                    return new UpdateResult
                    {
                        IsSuccess = false,
                        Message = $"加载文件失败：{loadResult.Message}",
                        TargetPath = fullPropPath
                    };
                }
                rootNode = loadResult.RootNode;

                // 步骤4：定位父对象并校验
                var parentNode = rootNode.SelectToken(parentPath);
                if (parentNode == null)
                {
                    return new UpdateResult
                    {
                        IsSuccess = false,
                        Message = $"未找到父对象路径 -> {parentPath}",
                        TargetPath = fullPropPath
                    };
                }
                if (parentNode.Type != JTokenType.Object)
                {
                    return new UpdateResult
                    {
                        IsSuccess = false,
                        Message = $"父路径不是对象（无法新增属性）-> {parentPath}（当前类型：{GetNodeType(parentNode)}）",
                        TargetPath = fullPropPath
                    };
                }
                JObject parentObj = (JObject)parentNode;

                // 步骤5：检查目标属性是否已存在
                var existingPropNode = parentObj[targetPropName];
                if (existingPropNode != null)
                {
                    // 场景A：属性已存在 → 执行更新
                    oldValue = existingPropNode.ToString(Formatting.None);
                    if (!IsValueTypeMatch(existingPropNode, propValue))
                    {
                        return new UpdateResult
                        {
                            IsSuccess = false,
                            Message = $"属性类型不匹配（当前类型：{GetNodeType(existingPropNode)}，新值类型：{propValue.GetType().Name}）",
                            TargetPath = fullPropPath,
                            OldValue = oldValue,
                            NewValue = newValueStr
                        };
                    }
                    // 更新属性值
                    parentObj[targetPropName] = JToken.Parse(newValueStr);
                    return ExecuteSaveAndVerify(jsonFilePath, rootNode, fullPropPath, oldValue, newValueStr, "更新");
                }
                else
                {
                    // 场景B：属性不存在 → 执行新增
                    oldValue = "（属性不存在）";
                    // 将属性值转为JToken并添加到父对象
                    parentObj.Add(targetPropName, JToken.Parse(newValueStr));
                    return ExecuteSaveAndVerify(jsonFilePath, rootNode, fullPropPath, oldValue, newValueStr, "新增");
                }
            }
            catch (JsonReaderException ex)
            {
                return new UpdateResult
                {
                    IsSuccess = false,
                    Message = $"JSON格式错误：{ex.Message}",
                    TargetPath = fullPropPath,
                    OldValue = oldValue,
                    NewValue = newValueStr
                };
            }
            catch (Exception ex)
            {
                return new UpdateResult
                {
                    IsSuccess = false,
                    Message = $"新增/更新属性失败：{ex.Message}",
                    TargetPath = fullPropPath,
                    OldValue = oldValue,
                    NewValue = newValueStr
                };
            }
        }

        /// <summary>
        /// 验证JSON节点与新值的类型是否匹配
        /// </summary>
        private static bool IsValueTypeMatch(JToken node, object newValue)
        {
            // 处理空节点情况
            if (node == null)
                return newValue == null;

            switch (node.Type)
            {
                // 数值类型匹配：int/long/float/double/decimal
                case JTokenType.Integer:
                case JTokenType.Float:
                    return newValue is int
                        || newValue is long
                        || newValue is float
                        || newValue is double
                        || newValue is decimal;

                // 字符串类型匹配
                case JTokenType.String:
                    return newValue is string;

                // 布尔类型匹配
                case JTokenType.Boolean:
                    return newValue is bool;

                // Null类型匹配
                case JTokenType.Null:
                    return newValue == null;

                // 对象/数组不在这里校验
                default:
                    return false;
            }
        }

        /// <summary>
        /// 加载JSON文件并校验（格式、可读性）
        /// </summary>
        private static (bool IsSuccess, JToken RootNode, string Message) LoadJsonWithCheck(string jsonFilePath)
        {
            try
            {
                // 校验文件是否可读
                if (!IsFileReadable(jsonFilePath))
                {
                    return (false, null, $"文件不可读（可能无权限或被占用）-> {jsonFilePath}");
                }

                // 读取文件内容
                string content = File.ReadAllText(jsonFilePath);
                if (string.IsNullOrWhiteSpace(content))
                {
                    return (false, null, "文件内容为空，无法解析JSON");
                }

                // 解析JSON并校验格式
                //JsonSerializerSettings settings = new JsonSerializerSettings
                //{
                //    AllowTrailingCommas = true,
                //    MaxDepth = 64 // 限制最大深度，避免恶意JSON攻击
                //};

                JToken rootNode = JToken.Parse(content);

                // 额外验证一下，确保解析成功
                if (rootNode == null)
                {
                    return (false, null, "JSON格式无效（语法错误或无法解析）");
                }

                return (true, rootNode, "文件加载成功");
            }
            catch (JsonReaderException ex)
            {
                return (false, null, $"JSON格式错误 -> {ex.Message}");
            }
            catch (Exception ex)
            {
                return (false, null, $"加载文件失败 -> {ex.Message}");
            }
        }

        /// <summary>
        /// 基础信息校验（文件路径、目标路径格式）
        /// </summary>
        private static UpdateResult ValidateBaseInfo(string jsonFilePath, string targetPath)
        {
            // 校验文件路径
            if (string.IsNullOrWhiteSpace(jsonFilePath))
            {
                return new UpdateResult
                {
                    IsSuccess = false,
                    Message = "基础校验失败：JSON文件路径不能为空",
                    TargetPath = targetPath
                };
            }
            if (!File.Exists(jsonFilePath))
            {
                return new UpdateResult
                {
                    IsSuccess = false,
                    Message = $"基础校验失败：文件不存在 -> {jsonFilePath}",
                    TargetPath = targetPath
                };
            }
            // 校验目标路径格式（必须以 $. 开头，符合JSON Path规范）
            if (string.IsNullOrWhiteSpace(targetPath) || !targetPath.StartsWith("$.", StringComparison.Ordinal))
            {
                return new UpdateResult
                {
                    IsSuccess = false,
                    Message = $"基础校验失败：目标路径格式错误（需以 $. 开头，例：$.app.user）",
                    TargetPath = targetPath
                };
            }
            return new UpdateResult { IsSuccess = true };
        }

        /// <summary>
        /// 获取节点的具体类型（用于错误提示）
        /// </summary>
        private static string GetNodeType(JToken node)
        {
            if (node == null)
                return "Null";

            switch (node.Type)
            {
                case JTokenType.Object:
                    return "Object（对象）";
                case JTokenType.Array:
                    return "Array（数组）";
                case JTokenType.Integer:
                case JTokenType.Float:
                    return "Number（数值）";
                case JTokenType.String:
                    return "String（字符串）";
                case JTokenType.Boolean:
                    return "Boolean（布尔）";
                case JTokenType.Null:
                    return "Null";
                default:
                    return "Unknown（未知）";
            }
        }

        /// <summary>
        /// 复用保存和校验逻辑（减少代码重复）
        /// </summary>
        private static UpdateResult ExecuteSaveAndVerify(string jsonFilePath, JToken rootNode, string targetPath, string oldValue, string newValueStr, string actionType)
        {
            // 保存文件
            var saveResult = SaveJsonWithCheck(jsonFilePath, rootNode);
            if (!saveResult.IsSuccess)
            {
                return new UpdateResult
                {
                    IsSuccess = false,
                    Message = $"{actionType}失败：{saveResult.Message}",
                    TargetPath = targetPath,
                    OldValue = oldValue,
                    NewValue = newValueStr
                };
            }

            // 校验结果
            var verifyResult = VerifyFileAfterUpdate(jsonFilePath, targetPath, newValueStr);
            if (!verifyResult.IsSuccess)
            {
                return new UpdateResult
                {
                    IsSuccess = false,
                    Message = $"{actionType}失败：{verifyResult.Message}",
                    TargetPath = targetPath,
                    OldValue = oldValue,
                    NewValue = newValueStr
                };
            }

            // 成功返回
            return new UpdateResult
            {
                IsSuccess = true,
                Message = $"{actionType}成功：属性已{actionType}并保存",
                TargetPath = targetPath,
                OldValue = oldValue,
                NewValue = newValueStr
            };
        }

        /// <summary>
        /// 保存JSON文件并校验（写入权限、文件完整性）
        /// </summary>
        private static (bool IsSuccess, string Message) SaveJsonWithCheck(string jsonFilePath, JToken rootNode)
        {
            try
            {
                // 校验文件是否可写
                if (!IsFileWritable(jsonFilePath))
                {
                    return (false, $"文件不可写（可能无权限或被占用）-> {jsonFilePath}");
                }

                // 使用Newtonsoft.Json序列化配置
                var serializerSettings = new JsonSerializerSettings
                {
                    Formatting = Formatting.Indented, // 缩进格式化
                    StringEscapeHandling = StringEscapeHandling.EscapeNonAscii, // 中文不转义
                    MaxDepth = 64
                };

                // 生成更新后的内容
                string updatedContent = JsonConvert.SerializeObject(rootNode, serializerSettings);

                // 写入临时文件（避免原文件损坏）
                string tempFilePath = $"{jsonFilePath}.tmp";
                File.WriteAllText(tempFilePath, updatedContent, Encoding.UTF8);

                // 校验临时文件是否写入成功
                if (!File.Exists(tempFilePath) || new FileInfo(tempFilePath).Length == 0)
                {
                    File.Delete(tempFilePath); // 清理无效临时文件
                    return (false, "临时文件写入失败，更新终止（避免原文件损坏）");
                }

                // 替换原文件
                if (File.Exists(jsonFilePath))
                {
                    File.Delete(jsonFilePath);
                }
                File.Move(tempFilePath, jsonFilePath);

                return (true, "文件保存成功");
            }
            catch (Exception ex)
            {
                // 异常时清理临时文件
                string tempFilePath = $"{jsonFilePath}.tmp";
                if (File.Exists(tempFilePath))
                {
                    File.Delete(tempFilePath);
                }
                return (false, $"保存文件失败 -> {ex.Message}");
            }
        }

        /// <summary>
        /// 更新后校验（重新读取文件，确认目标值已更新）
        /// </summary>
        private static (bool IsSuccess, string Message) VerifyFileAfterUpdate(string jsonFilePath, string targetPath, string expectedValue)
        {
            try
            {
                // 重新加载文件
                var loadResult = LoadJsonWithCheck(jsonFilePath);
                if (!loadResult.IsSuccess)
                {
                    return (false, $"重新加载文件失败：{loadResult.Message}");
                }

                // 定位目标节点并校验值
                var targetNode = loadResult.RootNode.SelectToken(targetPath);
                if (targetNode == null)
                {
                    return (false, "更新后未找到目标路径（可能节点被误删）");
                }

                string actualValue = targetNode.ToString(Formatting.None);
                if (!actualValue.Equals(expectedValue, StringComparison.Ordinal))
                {
                    string expectedPreview = expectedValue.Length > 50 ? $"{expectedValue.Substring(0, 50)}..." : expectedValue;
                    string actualPreview = actualValue.Length > 50 ? $"{actualValue.Substring(0, 50)}..." : actualValue;
                    return (false, $"更新后值不匹配（预期：{expectedPreview}，实际：{actualPreview}）");
                }

                return (true, "更新后文件校验通过");
            }
            catch (Exception ex)
            {
                return (false, $"校验更新结果失败 -> {ex.Message}");
            }
        }

        /// <summary>
        /// 检查文件是否可读
        /// </summary>
        private static bool IsFileReadable(string filePath)
        {
            if (!File.Exists(filePath))
                return false;

            try
            {
                using (FileStream stream = File.OpenRead(filePath))
                {
                    return true;
                }
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 检查文件是否可写
        /// </summary>
        private static bool IsFileWritable(string filePath)
        {
            // 文件存在：尝试打开写入流校验
            if (File.Exists(filePath))
            {
                try
                {
                    using (FileStream stream = File.OpenWrite(filePath))
                    {
                        return true;
                    }
                }
                catch
                {
                    return false;
                }
            }
            // 文件不存在：校验所在目录是否可写
            else
            {
                string directory = Path.GetDirectoryName(filePath);
                if (string.IsNullOrWhiteSpace(directory))
                    directory = Environment.CurrentDirectory;

                try
                {
                    string testFilePath = Path.Combine(directory, "temp_write_test.tmp");
                    File.WriteAllText(testFilePath, "test", Encoding.UTF8);
                    File.Delete(testFilePath);
                    return true;
                }
                catch
                {
                    return false;
                }
            }
        }
    }

}
